package com.simple.relaxed.slice;

import com.simple.relaxed.anno.*;
import com.simple.relaxed.anno.impl.AsyncTaskImpl;
import com.simple.relaxed.anno.impl.InjectImpl;
import com.simple.relaxed.anno.impl.PartLayoutImpl;
import com.simple.relaxed.exception.AnnotationAbsenceException;
import com.simple.relaxed.manager.impl.SliceManager;
import com.simple.relaxed.manager.impl.SliceModeManager;
import com.simple.relaxed.utils.AsyncTaskUtil;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.LayoutScatter;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.multimodalinput.event.TouchEvent;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 此框架中Slice的基类，用于创建AbilitySlice
 */
public abstract class BaseAbilitySlice extends AbilitySlice implements Component.TouchEventListener {

    /**
     * 表示任务在UI线程执行
     */
    public static final int UI_STACK = 0x001;

    /**
     * 表示任务在非UI线程执行
     */
    public static final int OTHER_STACK = 0x002;

    protected Component component;

    private Class<? extends BaseAbilitySlice> aClass;

    private Method resumeMethod;

    private Method pauseMethod;

    private Method touchMethod;

    protected TaskDispatcher uiTaskDispatcher;

    protected NoBackSliceEvent noBackSliceEvent = () -> {
        new ToastDialog(this).setText("没有可以回退的AbilitySlice").show();
    };

    @Override
    protected void onStart(Intent intent) {
        InjectImpl.inject(this);
        uiTaskDispatcher = getUITaskDispatcher();
        aClass = getClass();
        super.onStart(intent);
        initLayout();
        // 初始化Component
        initComponent();

        // 载入布局快
        PartLayoutImpl.partLayoutImpl(this);

        // 设定Component的初始值
        initComponentValue();

        // 设定Component点击事件
        initComponentClick();

        // 设定Component 长按事件
        initComponentLongClick();

        // 寻找被Resume注解标记的方法
        initSearchResume();

        // 寻找被Pause注解标记的方法
        intiSearchPause();

        // 寻找AsyncTask、BeforeTask、AfterTask三个注解标记的方法，并且注册到Manager中
        AsyncTaskImpl.asyncTask(this);

        // 寻找Slice的触摸事件的方法
        initSliceTouch();
    }

    @Override
    protected void onActive() {
        super.onActive();
        // 将自己添加入回退栈栈顶
        Slice slice = aClass.getDeclaredAnnotation(Slice.class);
        if (slice != null) {
            AbilitySlice abilitySlice = SliceModeManager.getInstance().lookupTop(slice.bindName());
            if (!aClass.isInstance(abilitySlice)) {
                SliceModeManager.getInstance().pushAbilitySlice(this);
            }
        }
        if (resumeMethod != null) {
            resumeMethod.setAccessible(true);
            try {
                resumeMethod.invoke(this);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        if (pauseMethod != null) {
            pauseMethod.setAccessible(true);
            try {
                pauseMethod.invoke(this);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 启动任务，通过bindName找到任务方法，并在指定的类型的线程中执行
     *
     * @param bindName        注册主任务时的名称
     * @param asyncTaskStack  主任务在哪一类线程运行，目前只有两类线程，即UI线程以及非UI线程（BaseAbilitySlice.UI_STACK 以及 BaseAbilitySlice.OTHER_STACK）
     * @param beforeTaskStack 主任务前置监听器运行在哪一类线程，目前只有两类线程，即UI线程以及非UI线程（BaseAbilitySlice.UI_STACK 以及 BaseAbilitySlice.OTHER_STACK）
     * @param afterTaskStack  主任务完成时，回调任务运行在哪一类线程，目前只有两类线程，即UI线程以及非UI线程（BaseAbilitySlice.UI_STACK 以及 BaseAbilitySlice.OTHER_STACK）
     */
    protected void runTask(String bindName, int asyncTaskStack, int beforeTaskStack, int afterTaskStack) {
        AsyncTaskUtil.runAsync(this, bindName, beforeTaskStack, asyncTaskStack, afterTaskStack);
    }

    /**
     * 使用此方法，启动本地ServiceAbility
     *
     * @param serviceClass 本地Service的类对象
     */
    protected void startServiceAbility(Class<? extends Ability> serviceClass) {
        String bundleName = getBundleName();
        Intent.OperationBuilder operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(bundleName)
                .withAbilityName(serviceClass);
        Intent intent = new Intent();
        intent.setOperation(operation.build());
        startAbility(intent);
    }

    /**
     * 调用此方法启动远程ServiceAbility
     *
     * @param deviceId    远程设备Id
     * @param bundlerName 远程App的包名
     * @param className   远程ServiceAbility的全类名，需要去除掉app的包名
     *                    例如：app包名 com.simple.relaxed 类名 com.simple.relaxed.service.ServiceBaseAbility
     *                    则此处的className则应该填入 service.ServiceBaseAbility，bundlerName应该填入 com.simple.relaxed
     */
    protected void startServiceAbility(String deviceId, String bundlerName, String className) {
        Intent.OperationBuilder operationBuilder = new Intent.OperationBuilder()
                .withDeviceId(deviceId)
                .withBundleName(bundlerName)
                .withAbilityName(className);
        Intent intent = new Intent();
        intent.setOperation(operationBuilder.build());
        startAbility(intent);
    }

    /**
     * 调用此方法，连接指定的ServiceAbility
     *
     * @param serviceAbility     指定ServiceAbility的类对象
     * @param iAbilityConnection 连接上时与断开时，会发生的回调对象
     */
    protected void connectService(Class<? extends Ability> serviceAbility, IAbilityConnection iAbilityConnection) {
        Intent.OperationBuilder operationBuilder = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(getBundleName())
                .withAbilityName(serviceAbility);
        Intent intent = new Intent();
        intent.setOperation(operationBuilder.build());
        connectAbility(intent, iAbilityConnection);
    }

    /**
     * 调用此方法，连接远程的ServiceAbility
     *
     * @param operation          连接信息携带者
     * @param iAbilityConnection 连接成功与断开连接时的回调对象
     */
    protected void connectService(Operation operation, IAbilityConnection iAbilityConnection) {
        Intent intent = new Intent();
        intent.setOperation(operation);
        connectAbility(intent, iAbilityConnection);
    }

    /**
     * 调用此方法创建远程连接信息携带者
     *
     * @param deviceId    远程设备id
     * @param bundlerName 远程设备上，被连接的app的包名
     * @param abilityName 远程设备上被连接的app的服务名它和bundlerName拼接成了被调用服务的完整类名
     * @return 远程连接信息携带者
     */
    protected Operation createOperation(String deviceId, String bundlerName, String abilityName) {
        Intent.OperationBuilder operationBuilder = new Intent.OperationBuilder()
                .withDeviceId(deviceId)
                .withBundleName(bundlerName)
                .withAbilityName(abilityName);
        return operationBuilder.build();
    }

    /**
     * 调用此方法启动跳转AbilitySlice
     *
     * @param bindName 注册时，绑定Slice组的对象
     * @param clazz    跳转的AbilitySlice的类对象
     */
    protected void startAbilitySlice(String bindName, Class<? extends AbilitySlice> clazz) {
        startAbilitySlice(bindName, clazz, new Intent());
    }

    /**
     * 调用此方法启动跳转AbilitySlice
     *
     * @param bindName 注册时，绑定Slice组的对象
     * @param clazz    跳转的AbilitySlice的类对象
     * @param intent   若要传递数据，则使用此对象，传递数据
     */
    protected void startAbilitySlice(String bindName, Class<? extends AbilitySlice> clazz, Intent intent) {
        Map<Class<? extends AbilitySlice>, SliceManager.Entry> lookup = SliceManager.getInstance().lookup(bindName);
        SliceManager.Entry entry = lookup.get(clazz);
        AbilitySlice slice = entry.getSlice();
        present(slice, intent);
    }

    /**
     * 调用此方法，使用回退栈模式，转入指定的AbilitySlice
     *
     * @param clazz 要转入的AbilitySlice的类对象
     */
    protected void startAbilitySliceUseStack(Class<? extends AbilitySlice> clazz) {
        startAbilitySliceUseStack(clazz, new Intent());
    }

    /**
     * 调用此方法，使用回退栈模式，转入指定的AbilitySlice，并且向其传递信息
     *
     * @param clazz  要转入的AbilitySlice的类对象
     * @param intent 要传递的消息的携带者
     */
    protected void startAbilitySliceUseStack(Class<? extends AbilitySlice> clazz, Intent intent) {
        AbilitySlice slice = SliceManager.getInstance().lookup(clazz);
        AbilitySlice abilitySlice = SliceModeManager.getInstance().pushAbilitySlice(slice);
        present(abilitySlice, intent);
    }

    /**
     * 调用此方法，返回到上一个AbilitySlice
     */
    protected void back() {
        back(new Intent());
    }

    /**
     * 调用此方法，返回到上一个AbilitySlice，并且向其传递信息
     *
     * @param intent 要传递的消息的携带者
     */
    protected void back(Intent intent) {
        Slice slice = aClass.getDeclaredAnnotation(Slice.class);
        if (slice == null) {
            throw new AnnotationAbsenceException("找不到注解".concat(Slice.class.getName()));
        }
        AbilitySlice abilitySlice = SliceModeManager.getInstance().pop(slice.bindName());
        if (abilitySlice == null) {
            noBackSliceEvent.noBackSlice();
            return;
        }
        present(abilitySlice, intent);
    }

    /**
     * 掉用此方法，返回到指定的AbilitySlice
     *
     * @param clazz 要返回的AbilitySlice
     */
    protected void backTo(Class<? extends AbilitySlice> clazz) {
        backTo(clazz, new Intent());
    }

    /**
     * 掉用此方法，返回到指定的AbilitySlice，并且向其传递消息
     *
     * @param clazz  要返回的AbilitySlice
     * @param intent 要传递的消息的携带者
     */
    protected void backTo(Class<? extends AbilitySlice> clazz, Intent intent) {
        Slice slice = aClass.getDeclaredAnnotation(Slice.class);
        if (slice == null) {
            throw new AnnotationAbsenceException("找不到注解".concat(Slice.class.getName()));
        }
        AbilitySlice abilitySlice = SliceModeManager.getInstance().backTo(clazz);
        if (abilitySlice == null) {
            noBackSliceEvent.noBackSlice();
            return;
        }
        present(abilitySlice, intent);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        boolean result = false;
        try {
            Object invoke = touchMethod.invoke(this, component, touchEvent);
            if (invoke instanceof Boolean) {
                result = (boolean) invoke;
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 寻找被标记了OnPause注解的方法
     */
    private void intiSearchPause() {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            OnPause onPause = method.getDeclaredAnnotation(OnPause.class);
            if (onPause == null) {
                continue;
            }
            pauseMethod = method;
        }
    }

    /**
     * 寻找被标记了OnResume注解的方法
     */
    private void initSearchResume() {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            OnResume onResume = method.getDeclaredAnnotation(OnResume.class);
            if (onResume == null) {
                continue;
            }
            resumeMethod = method;
            break;
        }
    }

    /**
     * 初始化当前Slice的主视图
     */
    private void initLayout() {
        Layout layout = aClass.getDeclaredAnnotation(Layout.class);
        if (layout == null) {
            throw new AnnotationAbsenceException("找不到注解：".concat(Layout.class.getName()));
        }
        int layoutId = layout.layoutId();
        component = LayoutScatter.getInstance(this).parse(layoutId, null, false);
        setUIContent((ComponentContainer) component);
    }

    /**
     * 自动注入当前Slice中被标记了OnLongClick注解的方法，为指定Component的长按事件
     */
    private void initComponentLongClick() {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            OnLongClick longClick = method.getDeclaredAnnotation(OnLongClick.class);
            if (longClick == null) {
                continue;
            }
            int componentId = longClick.componentId();
            Component c = findComponentById(componentId);
            c.setLongClickedListener((component) -> {
                method.setAccessible(true);
                int count = method.getParameterCount();
                try {
                    if (count == 0) {
                        method.invoke(this);
                    } else {
                        method.invoke(this, component);
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    /**
     * 自动注入当前Slice中被标记了OnClick注解的方法，为指定Component的点击事件
     */
    private void initComponentClick() {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            OnClick onClick = method.getDeclaredAnnotation(OnClick.class);
            if (onClick == null) {
                continue;
            }
            int componentId = onClick.componentId();
            Component component = findComponentById(componentId);
            component.setClickedListener((c) -> {
                method.setAccessible(true);
                int parameterCount = method.getParameterCount();
                try {
                    if (parameterCount == 0) {
                        method.invoke(this);
                    } else {
                        method.invoke(this, c);
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    /**
     * 自动触发被标记了InitValue注解得方法，主要用于做一些值初始化操作
     */
    private void initComponentValue() {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            InitValue initValue = method.getDeclaredAnnotation(InitValue.class);
            if (initValue == null) {
                continue;
            }
            method.setAccessible(true);
            try {
                method.invoke(this);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            break;
        }
    }

    /**
     * 此方法会寻找当前Slice中，携带了InitComponent注解的Filed，并且将指定Id的Component对象，注入到Filed中
     */
    private void initComponent() {
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            InitComponent component = field.getDeclaredAnnotation(InitComponent.class);
            if (component == null) {
                continue;
            }
            int componentId = component.componentId();
            Component c = findComponentById(componentId);
            field.setAccessible(true);
            try {
                field.set(this, c);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 调用此方法，搜索是否存在SliceTouch方法
     */
    private void initSliceTouch() {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            SliceTouch sliceTouch = method.getDeclaredAnnotation(SliceTouch.class);
            if (sliceTouch == null) {
                continue;
            }
            touchMethod = method;
            component.setTouchEventListener(this);
            break;
        }
    }

    public interface NoBackSliceEvent {

        void noBackSlice();
    }
}
